//! Trait implementation parser

use super::super::Parser;
use super::impl_decl::parse_impl_method;
use super::helpers::parse_where_clause_for_generics;
use crate::ast::decl::*;
use crate::error::{CompilerError, Result};
use crate::lexer::token::Token;

/// Parse trait implementation declaration (impl Trait for Type { ... })
pub fn parse_trait_impl_declaration(parser: &mut Parser) -> Result<TraitImpl> {
    parser.expect(&Token::Impl)?;

    // Parse trait name
    let trait_name = if let Some(Token::Identifier(name)) = parser.peek().map(|t| &t.token) {
        let name = name.clone();
        parser.advance()?;
        name
    } else {
        return Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected trait name after 'impl'",
        ));
    };

    // Expect 'for' keyword
    parser.expect(&Token::For)?;

    // Parse type name
    let for_type = if let Some(Token::Identifier(name)) = parser.peek().map(|t| &t.token) {
        let name = name.clone();
        parser.advance()?;
        name
    } else {
        return Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected type name after 'for'",
        ));
    };

    // Parse optional generic parameters
    let mut generics = if parser.consume(&Token::Less)? {
        let mut params = Vec::new();
        loop {
            if let Some(Token::Identifier(name)) = parser.peek().map(|t| &t.token) {
                let param_name = name.clone();
                parser.advance()?;

                let constraints = if parser.consume(&Token::Colon)? {
                    let mut constraint_list = Vec::new();
                    loop {
                        if let Some(constraint) = super::super::parse_type(parser)? {
                            constraint_list.push(constraint);
                        }
                        if !parser.consume(&Token::Plus)? {
                            break;
                        }
                    }
                    constraint_list
                } else {
                    Vec::new()
                };

                params.push(GenericParam {
                    name: param_name,
                    constraints,
                    location: parser.current_location(),
                });

                if !parser.consume(&Token::Comma)? {
                    break;
                }
            } else {
                break;
            }
        }
        parser.expect(&Token::Greater)?;
        params
    } else {
        Vec::new()
    };

    // Optional where-clause before '{'
    parse_where_clause_for_generics(parser, &mut generics)?;

    // Parse opening brace
    parser.expect(&Token::LeftBrace)?;

    // Parse methods
    let mut methods = Vec::new();
    while !parser.consume(&Token::RightBrace)? {
        if parser.is_at_end() {
            return Err(CompilerError::syntax(
                parser.current_location().line,
                parser.current_location().column,
                "Expected '}' to close impl block",
            ));
        }

        if parser.check(&Token::Fn) {
            let method = parse_impl_method(parser, &for_type)?;
            methods.push(method);
        } else {
            parser.advance()?;
        }
    }

    Ok(TraitImpl {
        trait_name,
        for_type,
        generics,
        methods,
        location: parser.current_location(),
    })
}
